/*
 * @Description: 路由相关工具类
 * @Author: Rfan
 * @Date: 2022-01-15 11:34:06
 * @LastEditTime: 2023-01-07 14:35:04
 */

import { ComponentType, createElement, Key, ReactNode } from 'react';
import Layout from '@/layout';
import { cloneDeep, sortBy } from 'lodash-es';
import lazyLoad from '@/routes/components/lazyLoad';
import { routerState } from '@/store/routerStore';
import { ItemType } from 'antd/lib/menu/hooks/useItems';
import * as AntdIcon from '@ant-design/icons';
import { IFuncNavResponse, IFuncNavTree, IRouteObj } from '@/routes/interface';
import { toJS } from 'mobx';
import { staticRoutes } from '@/routes';
import { jsonClone } from '@/utils/index';

/**
 * @description: 树结构路由表转换成数组，主要将path处理成为完整地址
 * @param {IRouteObj} Tree 树结构数据
 * @param {string} publicPath 转换后的扁平数组
 * @return {*}
 */
export function routerTreeToArr(Tree: IRouteObj[] = [], publicPath: string = ''): IRouteObj[] {
  const _list = jsonClone(Tree);
  return _list.reduce((arr: any[], node: any) => {
    const { path, children } = node;
    if (path) {
      node.path = `${publicPath}${path.indexOf('/') === 0 ? '' : '/'}${path || ''}`;
    } else {
      node.path = publicPath;
    }
    delete node.children;
    return arr.concat([node], children ? routerTreeToArr(children, node?.path || '') : []);
  }, []);
}

/**
 * @description: 根据路径查询路由
 * @param {string} path 树结构数据
 */
export const findRouterItem: (path: string) => IRouteObj | {} = (path) => {
  const routeNode = toJS(routerState.orgNavList).find((route) => route.rightsLink === path);
  const staticNode = routerTreeToArr(staticRoutes).find((route) => route.path === path);
  return (routeNode && orgNavItemToRouteItem(routeNode, -1)) || staticNode;
};

/**
 * @description: 获取路由不带参数的路由
 * @param {string} url
 * @return {*} search参数
 */
export function stripQueryAndHashFromPath(url: string): string {
  return url.split('?')[0].split('#')[0];
}

/**
 * @description: 将功能item或route item 处理为 menu item
 * @param {ReactNode} label
 * @param {Key} key
 * @param {ReactNode} icon
 * @param {ItemType} children
 * @return {ItemType}
 */
export const genNavItem = (
  label: ReactNode,
  key?: Key | null,
  icon?: ReactNode,
  children?: ItemType[]
): ItemType => {
  const selectIcon = AntdIcon[icon as keyof typeof AntdIcon];
  return {
    key,
    icon: icon && selectIcon ? createElement(selectIcon as ComponentType) : '',
    children,
    label
  } as ItemType;
};

/**
 * @description: 路由表转换为menu类型
 * @param {any[]} menuList
 * @param {ItemType[]} newArr
 * @param {string} basePath
 * @return {ItemType[]}
 */
export const routesArrToMenuArr = (
  menuList: any[],
  newArr: ItemType[] = [],
  basePath: string = ''
): ItemType[] => {
  menuList.forEach((item: any) => {
    if (!item.hidden) {
      if (item.path) {
        const _path =
          item.path.indexOf('/') === 0 ? `${basePath}${item.path}` : `${basePath}/${item.path}`;
        if (!item?.children?.length) {
          return newArr.push(genNavItem(item.meta?.title, _path, item.meta?.icon));
        }
        newArr.push(
          genNavItem(
            item.meta?.title,
            _path,
            item.meta?.icon,
            routesArrToMenuArr(item.children, [], _path)
          )
        );
      } else {
        if (item?.children?.length) {
          newArr.push(...routesArrToMenuArr(item.children));
        }
      }
    }
  });
  return newArr;
};

/**
 * @description: 处理后台返回菜单 key 值为 antd 菜单需要的 key 值
 * @param {IFuncNavTree[]} menuList
 * @param {ItemType[]} newArr
 * @return {ItemType[]}
 */
export const orgNavToMenu = (menuList: IFuncNavTree[], newArr: ItemType[] = []): ItemType[] => {
  menuList.forEach((item: IFuncNavTree) => {
    if (item.rightsLink) {
      if (!item?.children?.length) {
        return newArr.push(genNavItem(item.rightsName, item.rightsLink, item.rightsIcon));
      }
      newArr.push(
        genNavItem(
          item.rightsName,
          item.rightsLink,
          item.rightsIcon,
          orgNavToMenu(item.children, [])
        )
      );
    } else {
      if (item?.children?.length) {
        newArr.push(...orgNavToMenu(item.children));
      }
    }
  });
  return newArr;
};

/**
 * @description: -
 * @param {string} eleStr
 * @return {Promise<any>}
 */
const genElementComponent = async (eleStr: string): Promise<any> => {
  try {
    if (!eleStr || eleStr.indexOf('.') < 0) {
      return '';
    }
    const [fileName, routeName] = eleStr.split('.');
    const file: any = await import(`@/routes/modules/${fileName}`);

    return lazyLoad(file[routeName]);
  } catch (err) {
    console.log('find module', err);
  }
};

interface INavProps extends IFuncNavResponse {
  element: ReactNode;
  children?: IRouteObj[];
}

/**
 * @description: -
 * @param {INavProps} orgNavItem
 * @param {number} level
 * @return {IRouteObj}
 */
const orgNavItemToRouteItem = (orgNavItem: INavProps, level: number = 1): IRouteObj => {
  const isPageNode: boolean = !!orgNavItem.element;
  const element: ReactNode =
    level === 1 ? createElement(Layout) : isPageNode ? orgNavItem.element : '';

  return {
    path: orgNavItem.rightsLink?.split('?')[0] || '',
    element,
    meta: {
      keepAlive: orgNavItem.cacheRoute === 1,
      title: orgNavItem.rightsName,
      icon: orgNavItem.rightsIcon,
      isLink: orgNavItem.openMode === 2
    },
    children: orgNavItem.children
  };
};

/**
 * @description: 原始导航转换为路由表
 * @return {IRouteObj[]}
 */
export const orgNavToRoutes = (
  navList: IFuncNavTree[],
  newArr: IRouteObj[] = [],
  level: number = 1,
  parentNode?: IFuncNavTree
): IRouteObj[] => {
  for (let i = 0; i < navList.length; i++) {
    const item: IFuncNavTree = navList[i];
    // 没有子节点的
    if (!item?.children?.length) {
      if (level === 1) {
        const children = orgNavToRoutes([item], [], level + 1);
        newArr.push(
          orgNavItemToRouteItem(
            {
              ...item,
              children
            },
            level
          )
        );
      } else {
        if (item.element) {
          newArr.push(orgNavItemToRouteItem(item, level));
        }
      }
    } else {
      if (level === 1) {
        newArr.push(
          orgNavItemToRouteItem({
            ...item,
            children: orgNavToRoutes(item.children, [], level + 1, item)
          })
        );
      } else {
        newArr.push(...orgNavToRoutes(item.children, [], level + 1, parentNode || item));
      }
    }
  }
  return newArr;
};

/**
 * @description: 将返回的的导航中组件信息由字符串转换为组件
 * @param {IFuncNavTree} navTreeArr 原始导航
 * @param {IFuncNavTree} newArr 转换后的导航
 * @return {*}
 */
export const genNavComp = async (
  navTreeArr: IFuncNavTree[],
  newArr: IFuncNavTree[] = []
): Promise<IFuncNavTree[]> => {
  for (let i = 0; i < navTreeArr.length; i++) {
    const item = navTreeArr[i];
    if (item?.children?.length) {
      newArr.push({
        ...item,
        element: await genElementComponent(item.rightsComponent),
        children: await genNavComp(item.children, [])
      });
    } else {
      newArr.push({
        ...item,
        element: await genElementComponent(item.rightsComponent)
      });
    }
  }
  return newArr;
};

/**
 * @description 获取需要展开的 subMenu
 * @param {String} path 当前访问地址
 * @returns array
 */
export const getOpenKeys = (path: string) => {
  let newStr: string = '';
  const newArr: any[] = [];
  const arr = path.split('/');
  for (let i = 1; i < arr.length - 1; i++) {
    newStr += `/${arr[i]}`;
    newArr.push(newStr);
  }
  return newArr;
};

/**
 * @description: 扁平路由转树结构，支持排序
 * @param {any[]} arr 扁平数组
 * @return {any[]} 转换后的树结构
 */
export function flatRoutesToTree(arr: any[] = []): any[] {
  const _list = cloneDeep(arr);
  return sortBy(
    sortBy(
      _list
        .map((cur: any) => {
          const children = sortBy(
            sortBy(
              _list.filter((item: any) => item.pid === cur.id),
              ['id']
            ),
            ['sortNo']
          );

          if (children.length) {
            cur.children = children;
            flatRoutesToTree(children);
          }
          return cur;
        })
        .filter((item: any) => !item.pid),
      ['id']
    ),
    ['sortNo']
  );
}
